#include "apue.h"
#include <string.h>
#include <errno.h>
#include <stdarg.h>

// 只能在本模块内使用
static void err_doit(int, int, const char*, va_list);

/*
 * 不终止程序，打印消息后直接返回。
 */
void err_ret(const char *fmt, ...) {
    va_list argv;
    va_start(argv, fmt);
    err_doit(1, errno, fmt, argv);
    va_end(argv);
}

/*
 * 终止程序
 */
void err_sys(const char *fmt, ...) {
    va_list argv;
    va_start(argv, fmt);
    err_doit(1, errno, fmt, argv);
    va_end(argv);
    exit(1);
}

void err_cont(int error, const char *fmt, ...) {
    va_list argv;
    va_start(argv, fmt);
    err_doit(1, error, fmt, argv);
    va_end(argv);
}

void err_exit(int error, const char *fmt, ...) {
    va_list argv;
    va_start(argv, fmt);
    err_doit(1, error, fmt, argv);
    va_end(argv);
    exit(1);
}

void err_dump(const char *fmt, ...) {
    va_list argv;
    va_start(argv, fmt);
    err_doit(1, errno, fmt, argv);
    va_end(argv);
    abort();
    exit(1);
}

void err_msg(const char *fmt, ...) {
    va_list argv;
    va_start(argv, fmt);
    err_doit(0, 0, fmt, argv);
    va_end(argv);
}

void err_quit(const char *fmt, ...) {
    va_list argv;
    va_start(argv, fmt);
    err_doit(0, 0, fmt, argv);
    va_end(argv);
    exit(1);
}


static void err_doit(int errFlag, int error, const char *fmt, va_list ap) {
    char buf[MAXLINE];
    // 把不定长参数打印到数组中去
    vsnprintf(buf, MAXLINE - 1, fmt, ap);
    if(errFlag) {
        int bufLen = strlen(buf);
        snprintf(buf + bufLen, MAXLINE - bufLen - 1, ": %s", strerror(error));
    }
    strcat(buf, "\n");
    fflush(stdout); // 避免标准错误和标准错误指向同一个
    fputs(buf, stderr);
    fflush(0); // 刷新所有的标准输出缓冲区
}
